package org.sample.springbootdatabase.service;

import java.sql.Date;
import java.util.Collections;
import java.util.List;

import org.sample.springbootdatabase.domain.UserRepository;
import org.sample.springbootdatabase.domain.entity.User;
import org.sample.springbootdatabase.web.model.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

@Service
public class DatabaseUserService implements UserService {

	@Autowired
	private UserRepository repository;

	@Override
	public List<User> findAllUsers() {
		List<User> users = repository.findAll();
		updateLastAccessed(users);
		return users;
	}

	@Override
	public User findUserById(Long id) {
		User user = repository.findOne(id);
		updateLastAccessed(user);
		return user;
	}

	@Override
	public User findUserByName(String userName) {
		User user = repository.findByUserName(userName).get(0);
		updateLastAccessed(user);
		return user;
	}

	@Override
	public User saveUser(User userInfo) {
		return saveCreateDate(userInfo);
	}

	@Override
	public User createUser(UserDTO userDTO) {
		User user = new User();
		user.setUserName(userDTO.getUserName());
		if (!StringUtils.isEmpty(userDTO.getFirstName())) {
			user.setFirstName(userDTO.getFirstName());
		}
		if (!StringUtils.isEmpty(userDTO.getLastName())) {
			user.setLastName(userDTO.getLastName());
		}
		return saveCreateDate(user);
	}

	@Transactional(rollbackFor = { IllegalArgumentException.class })
	public User createUserWithRollback(UserDTO userDTO) {
		User user = createUser(userDTO);
		if (userDTO.getUserName().length() < 6) {
			throw new IllegalArgumentException("User name is too short. Data will rollback.");
		}
		return user;
	}

	@Transactional(noRollbackFor = { IllegalArgumentException.class })
	public User createUserWithoutRollback(UserDTO userDTO) {
		User user = createUser(userDTO);
		if (userDTO.getUserName().length() < 6) {
			throw new IllegalArgumentException("User name is too short. Data won't rollback.");
		}
		return user;
	}

	@Override
	public User updateUserById(User userInfo) {
		User user = repository.findOne(userInfo.getId());
		if (user == null) {
			return null;
		}

		if (!StringUtils.isEmpty(userInfo.getFirstName())) {
			user.setFirstName(userInfo.getFirstName());
		}
		if (!StringUtils.isEmpty(userInfo.getLastName())) {
			user.setLastName(userInfo.getLastName());
		}
		user = updateLastAccessed(user);

		return user;
	}

	@Override
	public User updateUserByName(UserDTO userDTO) {
		List<User> users = repository.findByUserName(userDTO.getUserName());
		if (users.isEmpty()) {
			return null;
		}

		User user = users.get(0);
		if (!StringUtils.isEmpty(userDTO.getFirstName())) {
			user.setFirstName(userDTO.getFirstName());
		}
		if (!StringUtils.isEmpty(userDTO.getLastName())) {
			user.setLastName(userDTO.getLastName());
		}
		user = updateLastAccessed(user);

		return user;
	}

	@Override
	public void deleteUserById(Long id) {
		repository.delete(id);
	}

	@Override
	public void deleteUserByName(String userName) {
		List<User> users = repository.findByUserName(userName);
		if (users.isEmpty()) {
			return;
		}

		repository.delete(users.get(0));
	}

	private User saveCreateDate(User user) {
		Date createDate = new Date(new java.util.Date().getTime());
		user.setCreatedDate(createDate);
		return updateLastAccessed(user);
	}

	private User updateLastAccessed(User user) {
		if (user == null) {
			return null;
		}
		Date lastAccessed = new Date(new java.util.Date().getTime());
		user.setLastAccessed(lastAccessed);
		return repository.save(user);
	}

	private List<User> updateLastAccessed(Iterable<User> users) {
		if (users == null) {
			return Collections.emptyList();
		}
		Date lastAccessed = new Date(new java.util.Date().getTime());
		for (User user : users) {
			user.setLastAccessed(lastAccessed);
		}
		return repository.save(users);
	}

	@Override
	public List<User> findByCreatedDate(java.util.Date createdDate) {
		return repository.findByCreatedDate(new Date(createdDate.getTime()));
	}

}
